#ifndef VARTAB_HPP
#define VARTAB_HPP
#include "types.hpp"
#include "properties.hpp"
#include <map>
#include <set>
#include <vector>

using namespace std;

/**
 * Acumula argumentos em uma lista para posterior comparação com os parâmetros
 * de uma função já declarada. É usado também na definição da função.
 */
class Arguments {
private:
    static vector<Properties*> _arglist;
public:
    static void reset();
    static void addarg(string name, Type* type);
    static vector<Properties*> arglist();
};

/**
 * Representa uma função. O operador de igualdade foi sobrecarregado de modo que,
 * duas funções são iguais se seus parâmetros são mutuamente compatíveis dois a
 * dois e seus nomes são iguais. Se comparada a uma lista de parâmetros, o
 * operador de igualdade atesta se os parâmetros são adequados a esta função.
 * Estes critérios de comparação permitem a sorecarga de funções.
 */
class Function {
private:
    string              _name;       // Identificador.
    string              _returner;   // Nome da variável de retorno.
    string              _exitpoint;  // Nome da label de saída da função.
    vector<Properties*> _parameters; // Lista de parâmetros.
    Type*               _returntype; // Tipo de retorno.
    string              _code;       // Código interno.
    string callcode(vector<Properties*> arguments);
    friend class SymbolTable;
public:
    Function(string name, vector<Properties*> p, Type* r, string c);
    string dec();
    string returner();
    bool operator ==(Function &other);
    bool operator ==(vector<Properties*> args);
};

/*
 * Monitorador de escopo. Atribui implicitamente um número a cada bloco de
 * função e provê um prefixo baseado neste número para adicionar à frente de
 * toda variável local de função, inclusive aos parâmetros, de forma a evitar
 * conflitos com a instância global.
 */
class Scope {
private:
    static bool _local;
    static int  _level;
public:
    static bool   atlocal();
    static int    level();
    static void   enterlocal();
    static void   changelocal();
    static void   leavelocal();
    static string preffix();
    static string returner();
};

/**
 * Provê informações sobre operações binárias e unárias dados os operandos e o
 * operador.
 */
class Operation {
public:
    static Type* binop(Properties &p1, Properties &t2, Operator op);
    static Type* unop(Properties &t1, Operator op);
    static string opstr(Operator op);
};

/**
 * Tabela de símbolos. Mantem controle sobre todos os símbolos (variáveis locais
 * e globais, temporárias, auxiliares de troca e funções) utilizadas no programa,
 * além de gerar o código para a declaração de todos estes.
 */
class SymbolTable {
private:
    static map<string, Type*>     _symbols;   // Variáveis locais e globais.
    static set<Function*>         _functions; // Funções.
    static map<Type*, int>        _temps;     // Variáveis temporárias.
    static map<Type*, string>     _swapaux;   // Auxiliares de troca.
public:
    // Insere uma variável. O escopo é determinado automaticamente com o auxílio
    // de Scope.
    static void insvar(string name, Type* type);
    // Insere uma função. Os parâmetros são obtidos de Arguments.
    static void insmap(string name, Type* type, string code);
    // Verifica se uma variável foi declarada, além de corrigir o nome de uma
    // variável local.
    static Properties* checkvar(string name);
    // Obtém todas as declarações.
    static string allcdecs();
    // Gera código para chamada de função.
    static Properties* invoke(string name);
    // Cria nova temporária de um dado tipo.
    static string newtemp(Type*);
    // Obtém o nome da variável auxiliar de troca do tipo dado.
    static string swapaux(Type*);
};

#endif /* VARTAB_HPP */
